#include "iinputmanager.h"
#include "util/assert.h"
#include <windows.h>
#include <XInput.h>

namespace gecko
{

	IInputManager::IInputManager()
		: m_numEvents(0)
	{
		// clear out action mappings
		memset(m_mappedActions, Evt_Invalid, sizeof(int) * MAX_CONTEXTS * Evt_NUM);

		// clear out contexts
		memset(m_playerContexts, 0, sizeof(int) * MAX_PLAYERS);
	}

	bool IInputManager::Initialise()
	{
		InitialiseDevices();
		return true;
	}

	bool IInputManager::Destroy()
	{
		DestroyDevices();
		return true;
	}

	void IInputManager::AddListener( IInputListener * listener, PlayerID playerID )
	{
		listener->m_playerID = playerID;
		m_listeners.PushBack(listener);
	}

	void IInputManager::Update(const float /*dt*/)
	{
		PollDevices();
		DispatchEvents();
	}

	void IInputManager::QueueEvent( const InputEvent & e )
	{
		int mappedAction = m_mappedActions[m_playerContexts[e.playerID]][e.inputID];

		// only queue if a mapped action exists
		if (mappedAction != Evt_Invalid)
		{
			// check for dupes (crappy slow method)
			for (int i = 0; i < m_numEvents; i++)
			{
				if (m_inputEvents[i].inputID == mappedAction)
				{
					return;
				}
			}

			int currentEvent = m_numEvents++;
			m_inputEvents[currentEvent] = e;

			// remap the id
			m_inputEvents[currentEvent].inputID = mappedAction;
		}
	}

	void IInputManager::DispatchEvents()
	{
		// TODO: prevent duplicate actions being dispatched
		for (int i = 0; i < m_numEvents; i++)
		{
			for (Listeners::Iterator itr = m_listeners.Begin(); itr != m_listeners.End(); ++itr)
			{
				if (m_inputEvents[i].playerID == (*itr)->m_playerID || (*itr)->m_playerID == PlayerID_All)
				{
					(*itr)->OnAction(m_inputEvents[i]);
				}
			}
		}

		m_numEvents = 0;
	}

	void IInputManager::SetActionMapping( int context, int inputEvent, int actionID )
	{
		Assert(context < MAX_CONTEXTS, "Exceeded maximum contexts");
		Assert(inputEvent < Evt_NUM, "Exceeded maximum event ID");

		m_mappedActions[context][inputEvent] = actionID;
	}

	void IInputManager::SetPlayerContext( PlayerID playerID, int contextID )
	{
		if (playerID == PlayerID_All)
		{
			for (int i = 0; i < MAX_PLAYERS; i++)
			{
				m_playerContexts[i] = contextID;
			}
		}
		else
		{
			m_playerContexts[playerID] = contextID;
		}
	}

}